package com.srit.recipes.service.impl;

import com.alibaba.excel.EasyExcel;
import com.srit.recipes.common.excel.ProcurementExportAll;
import com.srit.recipes.common.excel.ProcurementExportDay;
import com.srit.recipes.common.exception.RecipesException;
import com.srit.recipes.common.parent.DaoInject;
import com.srit.recipes.common.response.JpaPage;
import com.srit.recipes.entity.*;
import com.srit.recipes.service.BaseService;
import com.srit.recipes.service.ProcurementService;
import com.srit.recipes.vo.RecipesOverviewIngredient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ProcurementServiceImpl extends DaoInject implements ProcurementService {
    @Autowired
    private BaseService baseService;

    @Override
    public Object createProcurement(int id) {
        WeekRecipes weekRecipes = weekRecipesDao.getById(id);
        if (weekRecipes == null) {
            throw RecipesException.of("can not found");
        }

        if (weekRecipes.getState() != WeekRecipes.EXAMINE_PASS) {
            throw RecipesException.of("菜谱审核未通过");
        }

        int perNum = weekRecipes.getPerNum();

        List<WeekRecipesDetail> recipesDetails = weekRecipesDetailDao.findAllByWeekRecipesId(id);


        Map<Integer, List<WeekRecipesDetail>> weekRecipesMap = recipesDetails.stream().collect(Collectors.groupingBy(WeekRecipesDetail::getWeek));

        List<ProcurementDetailInfo> dailyProcurement = new ArrayList<>();
        for (Map.Entry<Integer, List<WeekRecipesDetail>> entry : weekRecipesMap.entrySet()) {
            Integer week = entry.getKey();

            Map<String, RecipesOverviewIngredient> ingredientMap = RecipesAnalysisImpl.calculateWithSc(entry.getValue(), baseService, perNum);

            dailyProcurement.addAll(ingredientMap.values().stream().map(x -> {
                ProcurementDetailInfo procurementDetailInfo = new ProcurementDetailInfo();
                procurementDetailInfo.setName(x.getName());
                procurementDetailInfo.setUnit(x.getUnit());
                procurementDetailInfo.setWight(x.getWight());
                procurementDetailInfo.setRecipesId(id);
                procurementDetailInfo.setWeek(week);
                return procurementDetailInfo;
            }).collect(Collectors.toList()));

        }

        procurementDetailDao.saveAll(dailyProcurement);
        return true;
    }


    @Override
    public Object procurementDetail(ProcurementDetailInfo procurementDetailInfo, JpaPage jpaPage) {
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains());

        Example<ProcurementDetailInfo> example = Example.of(procurementDetailInfo, exampleMatcher);
        Page<ProcurementDetailInfo> all = procurementDetailDao.findAll(example, JpaPage.getPageable(jpaPage));
        List<ProcurementDetailInfo> content = all.getContent();

        addExtra(content);
        return JpaPage.build(all);
    }

    private void addInventoryLeft(Map<String, Long> leftMap, ProcurementDetailInfo detailInfo) {
        Long left = leftMap.computeIfAbsent(detailInfo.getName(), s -> {
            List<InventoryInfo> allByName = inventoryDao.findAllByName(detailInfo.getName());
            if (allByName != null) {
                return allByName.stream().map(InventoryInfo::getWight).reduce(0L, Long::sum);
            }
            return 0L;
        });
        detailInfo.setInventoryLeft(left);
        detailInfo.setWight(detailInfo.getWight());
    }

    @Override
    public Object procurementDelete(int id) {
        procurementDetailDao.deleteByRecipesId(id);
        return true;
    }

    @Override
    public Object updateProcurement(ProcurementDetailInfo procurementDetailInfo) {
        return procurementDetailDao.save(procurementDetailInfo);
    }

    @Override
    public Object procurementDetailDelete(int id) {
        procurementDetailDao.deleteById(id);
        return true;
    }

    @Override
    public Object recipesProcurementList(JpaPage jpaPage) {
        return JpaPage.build(weekRecipesDao.findAllByProcurementState(WeekRecipes.IN_EXAMINE, JpaPage.getPageable(jpaPage, Sort.by("createTime").descending())));
    }

    @Override
    public Object submitProcurementExamine(int id) {
        WeekRecipes weekRecipes = weekRecipesDao.getById(id);
        if (weekRecipes == null) {
            throw RecipesException.of("can not found recipes");
        }

        if (weekRecipes.getState() != WeekRecipes.EXAMINE_PASS) {
            throw RecipesException.of("菜谱审核未通过");
        }


        weekRecipes.setProcurementState(WeekRecipes.IN_EXAMINE);
        return weekRecipesDao.save(weekRecipes);
    }

    @Override
    public Object procurementExamine(WeekRecipes weekRecipes) {
        WeekRecipes save = weekRecipesDao.getById(weekRecipes.getId());
        save.setProcurementState(weekRecipes.getState());
        save.setProExamineMsg(weekRecipes.getExamineMsg());
        weekRecipesDao.save(save);
        return save;
    }

    @Override
    public Object procurementExport(ProcurementDetailInfo procurementDetailInfo, HttpServletResponse response) throws Exception {
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains());

        Example<ProcurementDetailInfo> example = Example.of(procurementDetailInfo, exampleMatcher);
        List<ProcurementDetailInfo> content = procurementDetailDao.findAll(example);

        addExtra(content);

        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");

        WeekRecipes weekRecipes = weekRecipesDao.getById(procurementDetailInfo.getRecipesId());


        Collection<?> data = null;

        if (procurementDetailInfo.getWeek() == null) {
            Map<Integer, List<ProcurementDetailInfo>> dailyProMap = content.stream().collect(Collectors.groupingBy(ProcurementDetailInfo::getWeek));
            // 导出所有
            Map<String, ProcurementExportAll> allMap = new HashMap<>();

            for (Map.Entry<Integer, List<ProcurementDetailInfo>> entry : dailyProMap.entrySet()) {
                for (ProcurementDetailInfo detailInfo : entry.getValue()) {
                    ProcurementExportAll exportAll = allMap.computeIfAbsent(detailInfo.getName(), s -> {
                        ProcurementExportAll procurementExportAll = new ProcurementExportAll();
                        procurementExportAll.setName(detailInfo.getName());
                        procurementExportAll.setUnit(detailInfo.getUnit());
                        procurementExportAll.setInventoryLeft((int) detailInfo.getInventoryLeft());
                        procurementExportAll.setPrice(0D);
                        procurementExportAll.setTotalPrice(0D);
                        return procurementExportAll;
                    });

                    switch (entry.getKey()) {
                        case 0:
                            exportAll.setWeek1(detailInfo.getWight());
                            break;
                        case 1:
                            exportAll.setWeek2(detailInfo.getWight());
                            break;
                        case 2:
                            exportAll.setWeek3(detailInfo.getWight());
                            break;
                        case 3:
                            exportAll.setWeek4(detailInfo.getWight());
                            break;
                        case 4:
                            exportAll.setWeek5(detailInfo.getWight());
                            break;
                        case 5:
                            exportAll.setWeek6(detailInfo.getWight());
                            break;
                        case 6:
                            exportAll.setWeek7(detailInfo.getWight());
                            break;
                    }

                    exportAll.setPrice(detailInfo.getPrice());
                    exportAll.setTotal(exportAll.getTotal() + detailInfo.getWight());
                    exportAll.setTotalPrice(exportAll.getTotalPrice() + detailInfo.getPrice() * detailInfo.getWight() / 1000);


                }
                data = allMap.values();
            }
        } else {
            data = content.stream().map(x -> {
                ProcurementExportDay day = new ProcurementExportDay();
                day.setName(x.getName());
                day.setWight(Math.max(0, x.getWight() - x.getInventoryLeft()));
                day.setUnit(x.getUnit());
                day.setPrice(x.getPrice());
                day.setTotalPrice(day.getPrice() * day.getWight() / 1000);
                return day;
            }).collect(Collectors.toList());
        }


        try (OutputStream outputStream = response.getOutputStream()) {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(weekRecipes.getRecipesName() + "采购单.xlsx", "UTF-8"));
            if (procurementDetailInfo.getWeek() == null) {
                EasyExcel.write(outputStream, ProcurementExportAll.class).sheet("模板").doWrite(data);
            } else {
                EasyExcel.write(outputStream, ProcurementExportDay.class).sheet("模板").doWrite(data);
            }
        }
        return true;
    }

    public static void main(String[] args) throws IOException {
        File file = new File("123.xlsx");
        ProcurementDetailInfo detailInfo = new ProcurementDetailInfo();
        detailInfo.setName("123");
        ArrayList<ProcurementDetailInfo> objects = new ArrayList<>();
        objects.add(detailInfo);
        EasyExcel.write(Files.newOutputStream(file.toPath()), ProcurementDetailInfo.class).sheet("123").doWrite(objects);

    }

    public void addExtra(List<ProcurementDetailInfo> content) {
        Map<String, Long> leftMap = new HashMap<>();
        for (ProcurementDetailInfo detailInfo : content) {
            addInventoryLeft(leftMap, detailInfo);
            ScPriceInfo byId = scPriceDao.getById(detailInfo.getName());
            if (byId != null) {
                detailInfo.setPrice(byId.getPrice());
            } else {
                detailInfo.setPrice(0D);
            }
        }
    }
}
